
#include "Mapper.h"
#include "../Rom.h"
#include "assert.h"
#include "../savebundle.h"

void Mapper::SetPPUBank_8KB(const uint8_t bank) {
    uint16_t bank1kb = ((uint32_t)bank % mROM->chr8kbCount) << 3;
    mChrBank[0] = mROM->chrrom + (bank1kb + 0) * BANKSIZE_1KB;
    mChrBank[1] = mROM->chrrom + (bank1kb + 1) * BANKSIZE_1KB;
    mChrBank[2] = mROM->chrrom + (bank1kb + 2) * BANKSIZE_1KB;
    mChrBank[3] = mROM->chrrom + (bank1kb + 3) * BANKSIZE_1KB;
    mChrBank[4] = mROM->chrrom + (bank1kb + 4) * BANKSIZE_1KB;
    mChrBank[5] = mROM->chrrom + (bank1kb + 5) * BANKSIZE_1KB;
    mChrBank[6] = mROM->chrrom + (bank1kb + 6) * BANKSIZE_1KB;
    mChrBank[7] = mROM->chrrom + (bank1kb + 7) * BANKSIZE_1KB;
}

void Mapper::OnReset() {
    SetCPUBank_16KB(0, 0);
    SetCPUBank_16KB(1, mROM->prg16kbCount - 1);
    SetPPUBank_4KB(0, 0);
    SetPPUBank_4KB(1, 1);
}

void Mapper::Reset() {
    memset(mSaveRAM, 0, sizeof(mSaveRAM));
    memset(mExRAM, 0, sizeof(mExRAM));
    memset(mBusRAM, 0, sizeof(mBusRAM));
    OnReset();
}

void Mapper::Write6000(uint16_t address, uint8_t data) {
    if (address >= 0x4020 && address <= 0x41FF) {
        mBusRAM[address & 0x1FF] = data;
    }
    else if (address >= 0x5000 && address <= 0x5FFF) {
        //DebugPrintf("Write6000 %x\n", address);
        mExRAM[address & 0xFFF] = data;
    }
    else if (address >= 0x6000 && address <= 0x7FFF) {
        mSaveRAM[address & 0x1FFF] = data; //没必要减去6000 反正结果一样
    }
}

uint8_t Mapper::Read6000(uint16_t address) {
    if (address >= 0x4020 && address <= 0x41FF) {
        return mBusRAM[address & 0x1FF];
    }
    else if (address >= 0x5000 && address <= 0x5FFF) {
        //DebugPrintf("Read6000 %x\n",address);
        return mExRAM[address & 0xFFF];
    }
    else if (address >= 0x6000 && address <= 0x7FFF) {
        return mSaveRAM[address & 0x1FFF]; //没必要减去6000 反正结果一样
    }
    return 0;
}

void Mapper::WriteViaCPU(uint16_t address, uint8_t data) {
    //const uint16_t realaddress = address - 0x8000;
    mPrgBank[(address & 0x7FFF) >> 13][address & 0x1FFF] = data;
}

uint8_t Mapper::ReadViaPPU(uint16_t address) {
    return mChrBank[address >> 10][address & 0x3FF];
}

void Mapper::WriteViaPPU(uint16_t address, uint8_t data) {
    //if(mROM->isChrRAM)
    mChrBank[address >> 10][address & 0x3FF] = data;
    //else
    //	assert(!"不支持的地址");
}

void Mapper::Save(SaveBundle *bundle)
{

    this->OnSave(bundle);

    bundle->SaveBlock(mSaveRAM, sizeof(mSaveRAM));
    bundle->SaveBlock(mExRAM, sizeof(mExRAM));


    //保存CPU BANK相对指针偏移
    for (size_t i = 0; i < 4; i++)
    {
        bundle->SavePtr(mPrgBank[i] - mROM->prgrom);
    }

    //保存PPU BANK相对指针偏移
    for (size_t i = 0; i < 8; i++)
    {
        bundle->SavePtr(mChrBank[i] - mROM->chrrom);
    }
}

void Mapper::Restore(SaveBundle *bundle)
{
    this->OnRestore(bundle);

    bundle->RestoreBlock(mSaveRAM, sizeof(mSaveRAM));
    bundle->RestoreBlock(mExRAM, sizeof(mExRAM));

    for (size_t i = 0; i < 4; i++)
    {
        mPrgBank[i] = bundle->RestorePtr() + mROM->prgrom;
    }
    for (size_t i = 0; i < 8; i++)
    {
        mChrBank[i] = bundle->RestorePtr() + mROM->chrrom;
    }
}

void Mapper::OnSave(SaveBundle *bundle)
{
    //TODO
}

void Mapper::OnRestore(SaveBundle *bundle)
{
    //TODO
}
